package com.imddy.spbatch001.config;

import com.imddy.spbatch001.entity.BlogInfo;
import com.imddy.spbatch001.joblistener.MyJobListener;
import com.imddy.spbatch001.joblistener.MyReadListener;
import com.imddy.spbatch001.joblistener.MyWriteListener;
import jakarta.validation.Validator;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.item.validator.BeanValidatingItemProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import javax.sql.DataSource;
import java.util.Map;

@Configuration
public class SpringBatchConfig {


    /**
     * ItemReader定义：读取文件数据+entirty实体类映射
     * @return
     */
    @Bean
    public ItemReader<BlogInfo> reader(){
        // 使用FlatFileItemReader去读cvs文件，一行即一条数据
        FlatFileItemReader<BlogInfo> reader = new FlatFileItemReader<>();
        // 设置文件处在路径
        //reader.setResource(new ClassPathResource("static/bloginfo.csv"));
        reader.setResource(new FileSystemResource("D:/test005.csv"));
        // entity与csv数据做映射
        reader.setLineMapper(new DefaultLineMapper<BlogInfo>() {
            {
                setLineTokenizer(new DelimitedLineTokenizer() {
                    {
                        setNames(new String[]{"blogAuthor","blogUrl","blogTitle","blogItem"});
                    }
                });
                setFieldSetMapper(new BeanWrapperFieldSetMapper<BlogInfo>() {
                    {
                        setTargetType(BlogInfo.class);
                    }
                });
            }
        });
        return reader;
    }


    /**
     * ItemWriter定义：指定datasource，设置批量插入sql语句，写入数据库
     * @param dataSource
     * @return
     */
    @Bean
    public ItemWriter<BlogInfo> writer(DataSource dataSource){
        // 使用jdbcBcatchItemWrite写数据到数据库中
        JdbcBatchItemWriter<BlogInfo> writer = new JdbcBatchItemWriter<>();
        // 设置有参数的sql语句
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<BlogInfo>());
        String sql = "insert into bloginfo "+" (blogAuthor,blogUrl,blogTitle,blogItem) "
                +" values(:blogAuthor,:blogUrl,:blogTitle,:blogItem)";
        writer.setSql(sql);
        writer.setDataSource(dataSource);
        return writer;
    }


    @Bean
    public Validator beanValidator() {
        return new LocalValidatorFactoryBean();
    }

    /**
     * 注册ItemProcessor: 处理数据+校验数据
     * @return
     */
    @Bean
    public BeanValidatingItemProcessor<BlogInfo> processor() throws Exception {
        BeanValidatingItemProcessor<BlogInfo> processor = new BeanValidatingItemProcessor<>();
        processor.setFilter(true); // 跳过无效项
        processor.afterPropertiesSet(); // 初始化
        return processor;
    }



    // ================ Step配置 ================
    @Bean
    public Step myStep(
            JobRepository jobRepository,
            PlatformTransactionManager transactionManager,
            ItemReader<BlogInfo> reader,
            ItemProcessor<BlogInfo, BlogInfo> processor,
            ItemWriter<BlogInfo> writer) {

        return new StepBuilder("myStep", jobRepository)
                .<BlogInfo, BlogInfo>chunk(500, transactionManager) // 显式事务管理
                .reader(reader)
                .faultTolerant()
                .retryPolicy(new SimpleRetryPolicy(3, Map.of(Exception.class, true))) // 新版重试策略
                //.skipPolicy(new LimitCheckingSkipPolicy(2, Map.of(Exception.class, true))) // 新版跳过策略
                .skipLimit(2)
                .listener(new MyReadListener())
                .processor(processor)
                .writer(writer)
                .faultTolerant()
                .skip(Exception.class)
                .skipLimit(2)
                .listener(new MyWriteListener())
                .build();
    }

    // ================ Job配置 ================
    @Bean
    public Job myJob(JobRepository jobRepository, Step myStep) {
        return new JobBuilder("myJob", jobRepository)
                .incrementer(new RunIdIncrementer())
                .listener(new MyJobListener())
                .start(myStep)
                .build();
    }

















}
